import { Body, Controller, Delete, Get, HttpException, HttpStatus, Param, Post, Put, Query, UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { ApiBearerAuth, ApiOkResponse, ApiOperation, ApiTags } from '@nestjs/swagger';
import { RequestContext } from '../../../../context/request.context';
import { Authorities } from '../../../../decorators/authorities.decorator';
import { AuthoritiesGuard } from '../../../../guards/authorities.guard';
import { LantUtil } from '../../../../utils/lant.util';
import { BoolResDto } from '../../../common/dtos/bool.res.dto';
import { UuidReqDto } from '../../../common/dtos/uuid.req.dto';
import { UuidResDto } from '../../../common/dtos/uuid.res.dto';
import { Guard } from '../../../guard/constants/guard.constant';
import { LogAppender } from '../../../log/constants/log.constant';
import { LogService } from '../../../log/services/log.service';
import { OrganizationService } from '../../../organization/services/organization.service';
import { UserService } from '../../../user/services/user.service';
import { CreateOrUpdateAreaAdminReqDto } from '../../dtos/area/admin/create-or-update-area.admin.req.dto';
import { GetAreaListAdminReqDto } from '../../dtos/area/admin/get-area-list.admin.req.dto';
import { GetAreaListAdminResDto } from '../../dtos/area/admin/get-area-list.admin.res.dto';
import { AreaService } from '../../services/area.service';

@ApiBearerAuth()
@ApiTags('areas')
@Controller('admin/areas')
export class AreaAdminController {
  constructor(
    private readonly organizationService: OrganizationService,
    private readonly userService: UserService,
    private readonly areaService: AreaService,
    private readonly logService: LogService,
    private readonly lantUtil: LantUtil
  ) {}

  @ApiOperation({ summary: '创建一个区域' })
  @ApiOkResponse({ description: '返回新建区域的编号', type: UuidResDto })
  @Authorities(Guard.AreaManage)
  @UseGuards(AuthGuard(), AuthoritiesGuard)
  @Post()
  async create(@Body() { name }: CreateOrUpdateAreaAdminReqDto): Promise<UuidResDto> {
    try {
      const count = await this.areaService.checkDuplicateByName(name);
      if (count > 0) throw new HttpException(`${name}已存在，不能重复创建`, HttpStatus.BAD_REQUEST);

      const area = await this.areaService.create(name);

      return { uuid: area.uuid };
    } catch (error) {
      if (error instanceof HttpException) throw error;
      this.logService.error(LogAppender.area, `Cannot create area by ${name}, the error is ${error}`, this.lantUtil.parseError(error));
      throw new HttpException(error, HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }

  @ApiOperation({ summary: '删除一个区域' })
  @ApiOkResponse({ description: '返回删除结果', type: BoolResDto })
  @Authorities(Guard.AreaManage)
  @UseGuards(AuthGuard(), AuthoritiesGuard)
  @Delete(':uuid')
  async delete(@Param() { uuid }: UuidReqDto): Promise<BoolResDto> {
    try {
      const deleteResult = await this.areaService.deleteOneByUuid(uuid);

      return { result: !!deleteResult.affected };
    } catch (error) {
      if (error instanceof HttpException) throw error;
      this.logService.error(LogAppender.area, `Cannot delete area by ${uuid}, the error is ${error}`, this.lantUtil.parseError(error));
      throw new HttpException(error, HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }

  @ApiOperation({ summary: '更新一个区域' })
  @ApiOkResponse({ description: '返回更新结果', type: BoolResDto })
  @Authorities(Guard.AreaManage)
  @UseGuards(AuthGuard(), AuthoritiesGuard)
  @Put(':uuid')
  async update(@Param() { uuid }: UuidReqDto, @Body() { name }: CreateOrUpdateAreaAdminReqDto): Promise<BoolResDto> {
    try {
      const area = await this.areaService.findOneByUuid(uuid);
      if (!area) throw new HttpException('找不到指定的区域', HttpStatus.BAD_REQUEST);

      const count = await this.areaService.checkDuplicateByName(name, uuid);
      if (count > 0) throw new HttpException(`${name}已存在，不能重复创建`, HttpStatus.BAD_REQUEST);

      const updateResult = await this.areaService.update(uuid, name);

      return { result: !!updateResult.affected };
    } catch (error) {
      if (error instanceof HttpException) throw error;
      this.logService.error(LogAppender.area, `Cannot update area by ${JSON.stringify({ uuid, name })}, the error is ${error}`, this.lantUtil.parseError(error));
      throw new HttpException(error, HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }

  @ApiOperation({ summary: '获取区域列表' })
  @ApiOkResponse({ description: '返回区域列表', type: GetAreaListAdminResDto, isArray: true })
  @Authorities(Guard.AreaManage, Guard.AreaView)
  @UseGuards(AuthGuard(), AuthoritiesGuard)
  @Get()
  async getAll(@Query() query: GetAreaListAdminReqDto): Promise<GetAreaListAdminResDto> {
    try {
      const currentUser = RequestContext.currentUser();
      const organizationIdList = await this.organizationService.findDescendantsById(currentUser.jobId);

      const [areaList, count] = await this.areaService.findAndPaging(query.page_index, query.page_size, query.sort_type, query.name, organizationIdList);

      return {
        total_count: count,
        data: await Promise.all(
          areaList?.map(async area => {
            const creator = await this.userService.findOne(area.createdBy);
            return {
              uuid: area.uuid,
              name: area.name,
              description: area.description,
              created_by: creator?.displayName,
              created_at: area.createdAt,
              updated_at: area.updatedAt
            };
          })
        )
      };
    } catch (error) {
      if (error instanceof HttpException) throw error;
      this.logService.error(LogAppender.area, `Cannot get areas, the error is ${error}`, this.lantUtil.parseError(error));
      throw new HttpException(error, HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }
}
